use alloc::borrow::ToOwned;
use alloc::string::{String, ToString};
use cjson::Value;
use embed_std::ffi::CString;
use embed_std::Error;

pub fn get_json_str(root: &Value, field_name: &str) -> embed_std::Result<String> {
    let cname = CString::new(field_name).map_err(|err| Error::Other(err.to_string()))?;
    let v = root
        .get(cname.as_ptr())
        .ok_or(Error::NoJsonField(field_name.to_owned()))?;
    Ok(v.as_str()
        .ok_or(Error::InvalidJsonField(field_name.to_owned()))?
        .to_owned())
}

pub fn get_json_str_with_default(
    root: &Value,
    field_name: &str,
    def_val: &str,
) -> embed_std::Result<String> {
    let cname = CString::new(field_name).map_err(|err| Error::Other(err.to_string()))?;
    if let Some(v) = root.get(cname.as_ptr()) {
        if let Some(v) = v.as_str() {
            return Ok(v.to_owned());
        }
    }
    Ok(def_val.to_owned())
}

pub fn get_json_i64(root: &Value, field_name: &str) -> embed_std::Result<i64> {
    let cname = CString::new(field_name).map_err(|err| Error::Other(err.to_string()))?;
    let v = root
        .get(cname.as_ptr())
        .ok_or(Error::NoJsonField(field_name.to_owned()))?;
    Ok(v.as_i64()
        .ok_or(Error::InvalidJsonField(field_name.to_owned()))?
        .to_owned())
}

pub fn get_json_f64(root: &Value, field_name: &str) -> embed_std::Result<f64> {
    let cname = CString::new(field_name).map_err(|err| Error::Other(err.to_string()))?;
    let v = root
        .get(cname.as_ptr())
        .ok_or(Error::NoJsonField(field_name.to_owned()))?;
    Ok(v.as_f64()
        .ok_or(Error::InvalidJsonField(field_name.to_owned()))?
        .to_owned())
}

pub fn map_curl_error_to_std_err(e: curl::Error) -> Error {
    Error::Io(e.code() as i32, e.to_string())
}

pub fn map_curl_form_error_to_std_err(e: curl::FormError) -> Error {
    Error::Io(e.code() as i32, e.to_string())
}

pub fn map_curl_multi_error_to_std_err(e: curl::MultiError) -> Error {
    Error::Io(e.code() as i32, e.to_string())
}

pub fn map_string_error_to_std_err(e: String) -> Error {
    Error::Other(e)
}
